package com.pp.ent.view;

import android.app.Activity;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;


import com.pp.ent.base.inject.Injector;
import com.pp.ent.base.log.MLog;
import com.pp.ent.view.annotation.ContentView;
import com.pp.ent.view.annotation.EventBase;
import com.pp.ent.view.annotation.ViewInject;

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

/**
 * Author:dengqu
 * Date:2016/7/26
 */
public class InjectUtils {
    private static final String METHOD_SET_CONTENTVIEW = "setContentView";
    private static final String METHOD_FIND_VIEW_BY_ID = "findViewById";
    private final static String TAG = "InjectUtils";


    /**
     * activity注入，包含了view的注入
     *
     * @param activity
     */
    public static void injectActivity(Activity activity) {
        MLog.debug(TAG, "inject");
        injectContentView(activity);
        injectViews(activity);
        injectEvents(activity);
        injectObject(activity);
    }

    /**
     * fragment的布局注入
     *
     * @param fragment
     * @param inflater
     * @param container
     * @param savedInstanceState
     * @return
     */

    public static View injectFragment(Fragment fragment, LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        return injectContentView(fragment, inflater, container, savedInstanceState);
    }


    /**
     * 注入所有的service
     *
     * @param object
     */
    public static void injectObject(Object object) {
        try {
            Injector.doInject(object);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 注入所有的事件
     *
     * @param activity
     */
    private static void injectEvents(Activity activity) {

        Class<? extends Activity> clazz = activity.getClass();
        Method[] methods = clazz.getDeclaredMethods();
        //遍历所有的方法
        for (Method method : methods) {
            Annotation[] annotations = method.getAnnotations();
            //拿到方法上的所有的注解
            for (Annotation annotation : annotations) {
                Class<? extends Annotation> annotationType = annotation
                        .annotationType();
                //拿到注解上的注解
                EventBase eventBaseAnnotation = annotationType
                        .getAnnotation(EventBase.class);
                //如果设置为EventBase
                if (eventBaseAnnotation != null) {
                    //取出设置监听器的名称，监听器的类型，调用的方法名
                    String listenerSetter = eventBaseAnnotation
                            .listenerSetter();
                    Class<?> listenerType = eventBaseAnnotation.listenerType();
                    String methodName = eventBaseAnnotation.methodName();

                    try {
                        //拿到Onclick注解中的value方法
                        Method aMethod = annotationType
                                .getDeclaredMethod("value");
                        aMethod.setAccessible(true);
                        //取出所有的viewId
                        int[] viewIds = (int[]) aMethod
                                .invoke(annotation, null);
                        //通过InvocationHandler设置代理
                        DynamicHandler handler = new DynamicHandler(activity);
                        //往map添加方法
                        handler.addMethod(methodName, method);
                        Object listener = Proxy.newProxyInstance(
                                listenerType.getClassLoader(),
                                new Class<?>[]{listenerType}, handler);
                        //遍历所有的View，设置事件
                        for (int viewId : viewIds) {
                            View view = activity.findViewById(viewId);
                            Method setEventListenerMethod = view.getClass()
                                    .getMethod(listenerSetter, listenerType);
                            setEventListenerMethod.invoke(view, listener);
                        }

                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }

            }
        }

    }


    private static void injectEvents(Fragment fragment, View containerView) {
        Class<? extends Fragment> clazz = fragment.getClass();
        Method[] methods = clazz.getDeclaredMethods();
        //遍历所有的方法
        for (Method method : methods) {
            Annotation[] annotations = method.getAnnotations();
            //拿到方法上的所有的注解
            for (Annotation annotation : annotations) {
                Class<? extends Annotation> annotationType = annotation
                        .annotationType();
                //拿到注解上的注解
                EventBase eventBaseAnnotation = annotationType
                        .getAnnotation(EventBase.class);
                //如果设置为EventBase
                if (eventBaseAnnotation != null) {
                    //取出设置监听器的名称，监听器的类型，调用的方法名
                    String listenerSetter = eventBaseAnnotation
                            .listenerSetter();
                    Class<?> listenerType = eventBaseAnnotation.listenerType();
                    String methodName = eventBaseAnnotation.methodName();

                    try {
                        //拿到Onclick注解中的value方法
                        Method aMethod = annotationType
                                .getDeclaredMethod("value");
                        aMethod.setAccessible(true);
                        //取出所有的viewId
                        int[] viewIds = (int[]) aMethod
                                .invoke(annotation, null);
                        //通过InvocationHandler设置代理
                        DynamicHandler handler = new DynamicHandler(fragment);
                        //往map添加方法
                        handler.addMethod(methodName, method);
                        Object listener = Proxy.newProxyInstance(
                                listenerType.getClassLoader(),
                                new Class<?>[]{listenerType}, handler);
                        //遍历所有的View，设置事件
                        for (int viewId : viewIds) {
                            View view = containerView.findViewById(viewId);
                            Method setEventListenerMethod = view.getClass()
                                    .getMethod(listenerSetter, listenerType);
                            setEventListenerMethod.invoke(view, listener);
                        }

                    } catch (Exception e) {
                        MLog.error(TAG, e);
                    }
                }

            }
        }

    }


    /**
     * 注入所有的控件
     *
     * @param activity
     */
    private static void injectViews(Activity activity) {
        Class<? extends Activity> clazz = activity.getClass();
        Field[] fields = clazz.getDeclaredFields();
        // 遍历所有成员变量
        for (Field field : fields) {
            ViewInject viewInjectAnnotation = field
                    .getAnnotation(ViewInject.class);
            if (viewInjectAnnotation != null) {
                int viewId = viewInjectAnnotation.value();
                if (viewId != -1) {
                    // 初始化View
                    try {
                        Method method = clazz.getMethod(METHOD_FIND_VIEW_BY_ID,
                                int.class);
                        Object resView = method.invoke(activity, viewId);
                        field.setAccessible(true);
                        field.set(activity, resView);
                    } catch (Exception e) {
                        MLog.error(TAG,e);
                    }

                }
            }

        }

    }


    /**
     * 绑定view到fragment
     *
     * @param fragment
     * @param view
     */
    private static void injectViews(Fragment fragment, View view) {
        Class<? extends Fragment> clazz = fragment.getClass();
        Class<? extends View> clazzView = view.getClass();
        Field[] fields = clazz.getDeclaredFields();
        jnjectSuperView(fields,clazzView,view,fragment);
        for(Class<?> superClassz=clazz.getSuperclass();superClassz!=Object.class;superClassz=superClassz.getSuperclass()){
            Field[] superField=superClassz.getDeclaredFields();
            jnjectSuperView(superField,clazzView,view,fragment);
        }

    }


    private static void jnjectSuperView(Field[] fields,Class<? extends View> clazzView,View view, Fragment fragment){
        // 遍历所有成员变量
        for (Field field : fields) {
            ViewInject viewInjectAnnotation = field
                    .getAnnotation(ViewInject.class);
            if (viewInjectAnnotation != null) {
                int viewId = viewInjectAnnotation.value();
                if (viewId != -1) {
                    // 初始化View
                    try {
                        Method method = clazzView.getMethod(METHOD_FIND_VIEW_BY_ID,
                                int.class);
                        Object resView = method.invoke(view, viewId);
                        field.setAccessible(true);
                        field.set(fragment, resView);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }

                }
            }

        }

    }

    /**
     * 注入主布局文件
     *
     * @param activity
     */
    private static void injectContentView(Activity activity) {
        Class<? extends Activity> clazz = activity.getClass();
        // 查询类上是否存在ContentView注解
        ContentView contentView = clazz.getAnnotation(ContentView.class);
        if (contentView != null)// 存在
        {
            int contentViewLayoutId = contentView.value();
            try {
                Method method = clazz.getMethod(METHOD_SET_CONTENTVIEW, int.class);
                method.setAccessible(true);
                method.invoke(activity, contentViewLayoutId);
            } catch (Exception e) {
                MLog.error(TAG,e);
            }
        }
    }


    /**
     * fragment的view注入
     *
     * @param fragment
     * @param inflater
     * @param container
     * @param savedInstanceState
     * @return
     */
    private static View injectContentView(Fragment fragment, LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        Class<? extends Fragment> clazz = fragment.getClass();
        // 查询类上是否存在ContentView注解
        ContentView contentView = clazz.getAnnotation(ContentView.class);
        View view = null;
        if (contentView != null) {// 存在
            int contentViewLayoutId = contentView.value();
            try {
                view = inflater.inflate(contentViewLayoutId, container, false);
                injectViews(fragment, view);
                injectEvents(fragment, view);
                return view;
            } catch (Exception e) {
                MLog.error(TAG, e);
            }
        }
        return view;
    }


}
